package card

import (
	"core/command"
	"core/component/logger"
	"core/helper/conv"
	"sort"
	"strconv"
	"strings"
)

func (mgr *CardsMgr) SortStr(pokers string) (sortPokers string) {
	runeArr := make([]int, 0)
	for _, s := range pokers {
		runeArr = append(runeArr, int(s))
	}
	sort.Ints(runeArr)
	res := make([]byte, 0)
	for _, v := range runeArr {
		res = append(res, byte(v))
	}
	return string(res)
}

// 出的牌是否在手牌中存在
func (mgr *CardsMgr) IsContains(parent, child string) (result bool) {
	for _, childCard := range child {
		inHand := false
		for i, parentCard := range parent {
			if childCard == parentCard {
				inHand = true
				tmp := []byte(parent)
				copy(tmp[i:], tmp[i+1:])
				tmp = tmp[:len(tmp)-1]
				parent = string(tmp)
				break
			}
		}
		if !inHand {
			return
		}
	}
	return true
}

// 将牌编号转换为扑克牌
func (mgr *CardsMgr) ToPokers(num []int) string {
	totalCards := "A234567890JQK"
	res := make([]byte, 0)
	for _, poker := range num {
		if poker == 52 {
			res = append(res, 'w')
		} else if poker == 53 {
			res = append(res, 'W')
		} else {
			res = append(res, totalCards[poker%13])
		}
	}
	return string(res)
}

// 将牌转换为编号
func (mgr *CardsMgr) ToPoker(card byte) (poker []int) {
	if card == 'w' {
		return []int{52}
	}
	if card == 'W' {
		return []int{53}
	}
	cards := "A234567890JQK"
	for i, c := range []byte(cards) {
		if c == card {
			return []int{i, i + 13, i + 13*2, i + 13*3}
		}
	}
	return []int{54}
}

// 将机器人要出的牌转换为编号
func (mgr *CardsMgr) pokersInHand(num []int, findPokers string) (pokers []int) {
	var isInResPokers = func(poker int) bool {
		for _, p := range pokers {
			if p == poker {
				return true
			}
		}
		return false
	}

	for _, poker := range findPokers {
		poker := mgr.ToPoker(byte(poker))
	out:
		for _, pItem := range poker {
			for _, n := range num {
				if pItem == n && !isInResPokers(n) {
					pokers = append(pokers, pItem)
					break out
				}
			}
		}
	}
	return
}

// 获得牌型和大小
func (mgr *CardsMgr) PokersValue(pokers string) (cardType string, score int) {
	if combination, ok := mgr.pokerMap[mgr.SortStr(pokers)]; ok {
		cardType = combination.Type
		score = combination.Score
	}
	return
}

// 比较牌大小,并返回是否翻倍
func (mgr *CardsMgr) ComparePoker(baseNum, comparedNum []int) (int, bool) {
	logger.Debugf("comparedNum %v  %v", baseNum, comparedNum)
	if len(baseNum) == 0 || len(comparedNum) == 0 {
		if len(baseNum) == 0 && len(comparedNum) == 0 {
			return 0, false
		} else {
			if len(baseNum) != 0 {
				return -1, false
			} else {
				comparedType, _ := mgr.PokersValue(mgr.ToPokers(comparedNum))
				if comparedType == "rocket" || comparedType == "bomb" {
					return 1, true
				}
				return 1, false
			}
		}
	}
	baseType, baseScore := mgr.PokersValue(mgr.ToPokers(baseNum))
	comparedType, comparedScore := mgr.PokersValue(mgr.ToPokers(comparedNum))
	logger.Infof("compare poker %v, %v, %v, %v", baseType, baseScore, comparedType, comparedScore)
	if baseType == comparedType {
		return comparedScore - baseScore, false
	}
	if comparedType == "rocket" {
		return 1, true
	}
	if baseType == "rocket" {
		return -1, false
	}
	if comparedType == "bomb" {
		return 1, true
	}
	return 0, false
}

// 查找手牌中是否有比被比较牌型大的牌
func (mgr *CardsMgr) CardsAbove(handsNum, lastShotNum []int) (aboveNum []int) {
	handCards := mgr.ToPokers(handsNum)
	turnCards := mgr.ToPokers(lastShotNum)
	cardType, cardScore := mgr.PokersValue(turnCards)
	//logger.Infof("CardsAbove handsNum %v ,lastShotNum %v, handCards %v,cardType %v,turnCards %v",
	//	handsNum, lastShotNum, handCards, cardType, turnCards)
	if len(cardType) == 0 {
		return
	}
	for _, combination := range mgr.typeToPokers[cardType] {
		if combination.Score > cardScore && mgr.IsContains(handCards, combination.Poker) {
			aboveNum = mgr.pokersInHand(handsNum, combination.Poker)
			return
		}
	}
	if cardType != "boom" && cardType != "rocket" {
		for _, combination := range mgr.typeToPokers["boom"] {
			if mgr.IsContains(handCards, combination.Poker) {
				aboveNum = mgr.pokersInHand(handsNum, combination.Poker)
				return
			}
		}
	}
	if mgr.IsContains(handCards, "Ww") {
		aboveNum = mgr.pokersInHand(handsNum, "Ww")
		return
	}
	return
}

func (mgr *CardsMgr) initCardType() {
	cts := []string{"None", "pair", "seq_pair8", "seq_single6", "seq_trio_single5", "seq_pair9", "seq_single11", "bomb_single",
		"seq_trio_pair3", "seq_trio_single3", "seq_pair5", "trio", "seq_pair4", "seq_single10", "seq_trio_pair5", "seq_single12",
		"rocket", "trio_single", "seq_trio6", "seq_trio_pair4", "seq_trio_single4", "seq_single9", "seq_trio2", "bomb_pair", "seq_pair10",
		"seq_trio3", "single", "seq_pair6", "seq_pair7", "seq_trio4", "seq_single8", "seq_pair3", "seq_trio5", "seq_single7", "trio_pair", "bomb",
		"seq_trio_pair2", "seq_single5", "seq_trio_single2"}
	for cardty, cardStr := range cts {
		mgr.cardTypeMap[cardStr] = command.CardType(cardty)
	}
	mgr.robotCardTypeArray = append(mgr.robotCardTypeArray,
		"seq_trio_pair5", "seq_trio_pair4", "seq_trio_pair3", "seq_trio_pair2", "trio_pair", "seq_trio_single5", "seq_trio_single4",
		"seq_trio_single3", "seq_trio_single2", "seq_trio6", "seq_trio5", "seq_trio4", "seq_trio3", "seq_trio2", "trio_single", "trio",
		"seq_pair10", "seq_pair9", "seq_pair8", "seq_pair7", "seq_pair6", "seq_pair5", "seq_pair4", "seq_pair3", "seq_single12",
		"seq_single11", "seq_single10", "seq_single9", "seq_single8", "seq_single7", "seq_single6", "seq_single5", "pair", "bomb_pair", "bomb_single")
}

func (mgr *CardsMgr) CardTurnOff(cards []string) []int {
	cr := make([]int, 0)
	for _, c := range cards {
		val := strings.Split(c, "_")
		cValue2, _ := strconv.Atoi(val[2])
		if val[1] == "K" {
			cr = append(cr, cValue2-1)
		} else {
			cValue1, _ := strconv.Atoi(val[1])
			cr = append(cr, (cValue1-1)*13+cValue2-1)
		}
	}
	return cr
}

func (mgr *CardsMgr) GetCardTypeByC(cardType string) command.CardType {
	if cardType == "" {
		return command.CardType_error_type
	}
	if cardTy, ok := mgr.cardTypeMap[cardType]; ok {
		return cardTy
	}
	return command.CardType_error_type
}

// 机器人ai出牌
func (mgr *CardsMgr) RobotRandCards(handsNum []int) (aboveNum []int) {
	handCards := mgr.ToPokers(handsNum)
	if len(handsNum) <= 8 {
		var ty string
		switch len(handsNum) {
		case 8:
			ty = "bomb_pair"
		case 6:
			ty = "bomb_single"
		case 4:
			ty = "bomb"
		case 2:
			ty = "rocket"
		case 1:
			ty = "single"
		}
		if ty != "" {
			aboveNum = mgr.getAboveNum([]string{ty}, handsNum, handCards)
			if len(aboveNum) != 0 {
				return
			}
		}
	}
	aboveNum = mgr.getAboveNum(mgr.robotCardTypeArray, handsNum, handCards)
	if len(aboveNum) != 0 {
		return
	}
	aboveNum = mgr.getAboveNum([]string{"single"}, handsNum, handCards)
	return
}

func (mgr *CardsMgr) getAboveNum(tyArray []string, handsNum []int, handCards string) (aboveNum []int) {
	for _, cardType := range tyArray {
		for _, combination := range mgr.typeToPokers[cardType] {
			if mgr.IsContains(handCards, combination.Poker) {
				aboveNum = mgr.pokersInHand(handsNum, combination.Poker)
				return
			}
		}
	}
	return
}

// 初始化一副牌
func (mgr *CardsMgr) initCards() {
	start := 0
	for i := 1; i <= 14; i++ {
		if i == 14 {
			//大小王
			mgr.cards[start] = "Card_K_53"
			mgr.cards[start+1] = "Card_K_54"
		} else {
			mgr.cards[start] = "Card_1_" + conv.FormatInt(i)
			mgr.cards[start+1] = "Card_2_" + conv.FormatInt(i)
			mgr.cards[start+2] = "Card_3_" + conv.FormatInt(i)
			mgr.cards[start+3] = "Card_4_" + conv.FormatInt(i)
			start += 4
		}
	}
	logger.Info("初始化卡牌组成功")
}

func (mgr *CardsMgr) GetCards() []string {
	return mgr.cards
}
